home *** CD-ROM | disk | FTP | other *** search
/ Visual Cafe 3 / Visual Cafe 3.ISO / Vcafe / Main.bin / Utility.java < prev    next >
Text File  |  1998-09-22  |  16KB  |  454 lines

  1. /*
  2.  * @(#)Utility.java    1.5 98/01/12
  3.  *
  4.  * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
  5.  * (C) Copyright IBM Corp. 1996, 1997 - All Rights Reserved
  6.  *
  7.  * Portions copyright (c) 1996 Sun Microsystems, Inc. All Rights Reserved.
  8.  *
  9.  *   The original version of this source code and documentation is copyrighted
  10.  * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
  11.  * materials are provided under terms of a License Agreement between Taligent
  12.  * and Sun. This technology is protected by multiple US and International
  13.  * patents. This notice and attribution to Taligent may not be removed.
  14.  *   Taligent is a registered trademark of Taligent, Inc.
  15.  *
  16.  * Permission to use, copy, modify, and distribute this software
  17.  * and its documentation for NON-COMMERCIAL purposes and without
  18.  * fee is hereby granted provided that this copyright notice
  19.  * appears in all copies. Please refer to the file "copyright.html"
  20.  * for further important copyright and licensing information.
  21.  *
  22.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
  23.  * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
  24.  * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  25.  * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
  26.  * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
  27.  * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
  28.  *
  29.  */
  30. package java.text;
  31.  
  32. final class Utility {
  33.  
  34.     /**
  35.      * Convenience utility to compare two Object[]s.
  36.      * Ought to be in System
  37.      */
  38.     final static boolean arrayEquals(Object[] source, Object target) {
  39.         if (source == null) return (target == null);
  40.         if (!(target instanceof Object[])) return false;
  41.         Object[] targ = (Object[]) target;
  42.         return (source.length == targ.length
  43.                 && arrayRegionMatches(source, 0, targ, 0, source.length));
  44.     }
  45.  
  46.     /**
  47.      * Convenience utility to compare two int[]s
  48.      * Ought to be in System
  49.      */
  50.     final static boolean arrayEquals(int[] source, Object target) {
  51.         if (source == null) return (target == null);
  52.         if (!(target instanceof int[])) return false;
  53.         int[] targ = (int[]) target;
  54.         return (source.length == targ.length
  55.                 && arrayRegionMatches(source, 0, targ, 0, source.length));
  56.     }
  57.  
  58.     /**
  59.      * Convenience utility to compare two double[]s
  60.      * Ought to be in System
  61.      */
  62.     final static boolean arrayEquals(double[] source, Object target) {
  63.         if (source == null) return (target == null);
  64.         if (!(target instanceof double[])) return false;
  65.         double[] targ = (double[]) target;
  66.         return (source.length == targ.length
  67.                 && arrayRegionMatches(source, 0, targ, 0, source.length));
  68.     }
  69.  
  70.     /**
  71.      * Convenience utility to compare two Object[]s
  72.      * Ought to be in System
  73.      */
  74.     final static boolean arrayEquals(Object source, Object target) {
  75.         if (source == null) return (target == null);
  76.         // for some reason, the correct arrayEquals is not being called
  77.         // so do it by hand for now.
  78.         if (source instanceof Object[])
  79.             return(arrayEquals((Object[]) source,target));
  80.         if (source instanceof int[])
  81.             return(arrayEquals((int[]) source,target));
  82.         if (source instanceof double[])
  83.             return(arrayEquals((int[]) source,target));
  84.         return source.equals(target);
  85.     }
  86.  
  87.     /**
  88.      * Convenience utility to compare two Object[]s
  89.      * Ought to be in System.
  90.      * @param len the length to compare.
  91.      * The start indices and start+len must be valid.
  92.      */
  93.     final static boolean arrayRegionMatches(Object[] source, int sourceStart,
  94.                                             Object[] target, int targetStart,
  95.                                             int len)
  96.     {
  97.         int sourceEnd = sourceStart + len;
  98.         int delta = targetStart - sourceStart;
  99.         for (int i = sourceStart; i < sourceEnd; i++) {
  100.             if (!arrayEquals(source[i],target[i + delta]))
  101.             return false;
  102.         }
  103.         return true;
  104.     }
  105.  
  106.     /**
  107.      * Convenience utility to compare two int[]s.
  108.      * @param len the length to compare.
  109.      * The start indices and start+len must be valid.
  110.      * Ought to be in System
  111.      */
  112.     final static boolean arrayRegionMatches(int[] source, int sourceStart,
  113.                                             int[] target, int targetStart,
  114.                                             int len)
  115.     {
  116.         int sourceEnd = sourceStart + len;
  117.         int delta = targetStart - sourceStart;
  118.         for (int i = sourceStart; i < sourceEnd; i++) {
  119.             if (source[i] != target[i + delta])
  120.             return false;
  121.         }
  122.         return true;
  123.     }
  124.  
  125.     /**
  126.      * Convenience utility to compare two arrays of doubles.
  127.      * @param len the length to compare.
  128.      * The start indices and start+len must be valid.
  129.      * Ought to be in System
  130.      */
  131.     final static boolean arrayRegionMatches(double[] source, int sourceStart,
  132.                                             double[] target, int targetStart,
  133.                                             int len)
  134.     {
  135.         int sourceEnd = sourceStart + len;
  136.         int delta = targetStart - sourceStart;
  137.         for (int i = sourceStart; i < sourceEnd; i++) {
  138.             if (source[i] != target[i + delta])
  139.             return false;
  140.         }
  141.         return true;
  142.     }
  143.  
  144.     /**
  145.      * Convenience utility. Does null checks on objects, then calls equals.
  146.      */
  147.     final static boolean objectEquals(Object source, Object target) {
  148.     if (source == null)
  149.             return (target == null);
  150.     else
  151.             return source.equals(target);
  152.     }
  153.  
  154.     /**
  155.      * The ESCAPE character is used during run-length encoding.  It signals
  156.      * a run of identical chars.
  157.      */
  158.     static final char ESCAPE = '\uA5A5';
  159.  
  160.     /**
  161.      * The ESCAPE_BYTE character is used during run-length encoding.  It signals
  162.      * a run of identical bytes.
  163.      */
  164.     static final byte ESCAPE_BYTE = (byte)0xA5;
  165.  
  166.     /**
  167.      * Construct a string representing a short array.  Use run-length encoding.
  168.      * A character represents itself, unless it is the ESCAPE character.  Then
  169.      * the following notations are possible:
  170.      *   ESCAPE ESCAPE   ESCAPE literal
  171.      *   ESCAPE n c      n instances of character c
  172.      * Since an encoded run occupies 3 characters, we only encode runs of 4 or
  173.      * more characters.  Thus we have n > 0 and n != ESCAPE and n <= 0xFFFF.
  174.      * If we encounter a run where n == ESCAPE, we represent this as:
  175.      *   c ESCAPE n-1 c
  176.      * The ESCAPE value is chosen so as not to collide with commonly
  177.      * seen values.
  178.      */
  179.     static final String arrayToRLEString(short[] a) {
  180.     StringBuffer buffer = new StringBuffer();
  181.     // for (int i=0; i<a.length; ++i) buffer.append((char) a[i]);
  182.     buffer.append((char) (a.length >> 16));
  183.     buffer.append((char) a.length);
  184.     short runValue = a[0];
  185.     int runLength = 1;
  186.     for (int i=1; i<a.length; ++i) {
  187.         short s = a[i];
  188.         if (s == runValue && runLength < 0xFFFF) ++runLength;
  189.         else {
  190.         encodeRun(buffer, runValue, runLength);
  191.         runValue = s;
  192.         runLength = 1;
  193.         }
  194.     }
  195.     encodeRun(buffer, runValue, runLength);
  196.     return buffer.toString();
  197.     }
  198.  
  199.     /**
  200.      * Construct a string representing a byte array.  Use run-length encoding.
  201.      * Two bytes are packed into a single char, with a single extra zero byte at
  202.      * the end if needed.  A byte represents itself, unless it is the
  203.      * ESCAPE_BYTE.  Then the following notations are possible:
  204.      *   ESCAPE_BYTE ESCAPE_BYTE   ESCAPE_BYTE literal
  205.      *   ESCAPE_BYTE n b           n instances of byte b
  206.      * Since an encoded run occupies 3 bytes, we only encode runs of 4 or
  207.      * more bytes.  Thus we have n > 0 and n != ESCAPE_BYTE and n <= 0xFF.
  208.      * If we encounter a run where n == ESCAPE_BYTE, we represent this as:
  209.      *   b ESCAPE_BYTE n-1 b
  210.      * The ESCAPE_BYTE value is chosen so as not to collide with commonly
  211.      * seen values.
  212.      */
  213.     static final String arrayToRLEString(byte[] a) {
  214.     StringBuffer buffer = new StringBuffer();
  215.     buffer.append((char) (a.length >> 16));
  216.     buffer.append((char) a.length);
  217.     byte runValue = a[0];
  218.     int runLength = 1;
  219.     byte[] state = new byte[2];
  220.     for (int i=1; i<a.length; ++i) {
  221.         byte b = a[i];
  222.         if (b == runValue && runLength < 0xFF) ++runLength;
  223.         else {
  224.         encodeRun(buffer, runValue, runLength, state);
  225.         runValue = b;
  226.         runLength = 1;
  227.         }
  228.     }
  229.     encodeRun(buffer, runValue, runLength, state);
  230.  
  231.     // We must save the final byte, if there is one, by padding
  232.     // an extra zero.
  233.     if (state[0] != 0) appendEncodedByte(buffer, (byte)0, state);
  234.  
  235.     return buffer.toString();
  236.     }
  237.  
  238.     /**
  239.      * Encode a run, possibly a degenerate run (of < 4 values).
  240.      * @param length The length of the run; must be > 0 && <= 0xFFFF.
  241.      */
  242.     private static final void encodeRun(StringBuffer buffer, short value, int length) {
  243.     if (length < 4) {
  244.         for (int j=0; j<length; ++j) {
  245.         if (value == (int) ESCAPE) buffer.append(ESCAPE);
  246.         buffer.append((char) value);
  247.         }
  248.     }
  249.     else {
  250.         if (length == (int) ESCAPE) {
  251.         if (value == (int) ESCAPE) buffer.append(ESCAPE);
  252.         buffer.append((char) value);
  253.         --length;
  254.         }
  255.         buffer.append(ESCAPE);
  256.         buffer.append((char) length);
  257.         buffer.append((char) value); // Don't need to escape this value
  258.     }
  259.     }
  260.  
  261.     /**
  262.      * Encode a run, possibly a degenerate run (of < 4 values).
  263.      * @param length The length of the run; must be > 0 && <= 0xFF.
  264.      */
  265.     private static final void encodeRun(StringBuffer buffer, byte value, int length,
  266.                     byte[] state) {
  267.     if (length < 4) {
  268.         for (int j=0; j<length; ++j) {
  269.         if (value == ESCAPE_BYTE) appendEncodedByte(buffer, ESCAPE_BYTE, state);
  270.         appendEncodedByte(buffer, value, state);
  271.         }
  272.     }
  273.     else {
  274.         if (length == ESCAPE_BYTE) {
  275.         if (value == ESCAPE_BYTE) appendEncodedByte(buffer, ESCAPE_BYTE, state);
  276.         appendEncodedByte(buffer, value, state);
  277.         --length;
  278.         }
  279.         appendEncodedByte(buffer, ESCAPE_BYTE, state);
  280.         appendEncodedByte(buffer, (byte)length, state);
  281.         appendEncodedByte(buffer, value, state); // Don't need to escape this value
  282.     }
  283.     }
  284.  
  285.     /**
  286.      * Append a byte to the given StringBuffer, packing two bytes into each
  287.      * character.  The state parameter maintains intermediary data between
  288.      * calls.
  289.      * @param state A two-element array, with state[0] == 0 if this is the
  290.      * first byte of a pair, or state[0] != 0 if this is the second byte
  291.      * of a pair, in which case state[1] is the first byte.
  292.      */
  293.     private static final void appendEncodedByte(StringBuffer buffer, byte value,
  294.                         byte[] state) {
  295.     if (state[0] != 0) {
  296.         char c = (char) ((state[1] << 8) | (((int) value) & 0xFF));
  297.         buffer.append(c);
  298.         state[0] = 0;
  299.     }
  300.     else {
  301.         state[0] = 1;
  302.         state[1] = value;
  303.     }
  304.     }
  305.  
  306.     /**
  307.      * Construct an array of shorts from a run-length encoded string.
  308.      */
  309.     static final short[] RLEStringToShortArray(String s) {
  310.     int length = (((int) s.charAt(0)) << 16) | ((int) s.charAt(1));
  311.     short[] array = new short[length];
  312.     int ai = 0;
  313.     for (int i=2; i<s.length(); ++i) {
  314.         char c = s.charAt(i);
  315.         if (c == ESCAPE) {
  316.         c = s.charAt(++i);
  317.         if (c == ESCAPE) array[ai++] = (short) c;
  318.         else {
  319.             int runLength = (int) c;
  320.             short runValue = (short) s.charAt(++i);
  321.             for (int j=0; j<runLength; ++j) array[ai++] = runValue;
  322.         }
  323.         }
  324.         else {
  325.         array[ai++] = (short) c;
  326.         }
  327.     }
  328.  
  329.     if (ai != length)
  330.         throw new InternalError("Bad run-length encoded short array");
  331.  
  332.     return array;
  333.     }
  334.  
  335.     /**
  336.      * Construct an array of bytes from a run-length encoded string.
  337.      */
  338.     static final byte[] RLEStringToByteArray(String s) {
  339.     int length = (((int) s.charAt(0)) << 16) | ((int) s.charAt(1));
  340.     byte[] array = new byte[length];
  341.     boolean nextChar = true;
  342.     char c = 0;
  343.     int node = 0;
  344.     int runLength = 0;
  345.     int i = 2;
  346.     for (int ai=0; ai<length; ) {
  347.         // This part of the loop places the next byte into the local
  348.         // variable 'b' each time through the loop.  It keeps the
  349.         // current character in 'c' and uses the boolean 'nextChar'
  350.         // to see if we've taken both bytes out of 'c' yet.
  351.         byte b;
  352.         if (nextChar) {
  353.         c = s.charAt(i++);
  354.         b = (byte) (c >> 8);
  355.         nextChar = false;
  356.         }
  357.         else {
  358.         b = (byte) (c & 0xFF);
  359.         nextChar = true;
  360.         }
  361.  
  362.         // This part of the loop is a tiny state machine which handles
  363.         // the parsing of the run-length encoding.  This would be simpler
  364.         // if we could look ahead, but we can't, so we use 'node' to
  365.         // move between three nodes in the state machine.
  366.         switch (node) {
  367.         case 0:
  368.         // Normal idle node
  369.         if (b == ESCAPE_BYTE) {
  370.             node = 1;
  371.         }
  372.         else {
  373.             array[ai++] = b;
  374.         }
  375.         break;
  376.         case 1:
  377.         // We have seen one ESCAPE_BYTE; we expect either a second
  378.         // one, or a run length and value.
  379.         if (b == ESCAPE_BYTE) {
  380.             array[ai++] = ESCAPE_BYTE;
  381.             node = 0;
  382.         }
  383.         else {
  384.             runLength = b;
  385.             // Interpret signed byte as unsigned
  386.             if (runLength < 0) runLength += 0x100;
  387.             node = 2;
  388.         }
  389.         break;
  390.         case 2:
  391.         // We have seen an ESCAPE_BYTE and length byte.  We interpret
  392.         // the next byte as the value to be repeated.
  393.         for (int j=0; j<runLength; ++j) array[ai++] = b;
  394.         node = 0;
  395.         break;
  396.         }
  397.     }
  398.  
  399.     if (node != 0)
  400.         throw new InternalError("Bad run-length encoded byte array");
  401.  
  402.     if (i != s.length())
  403.         throw new InternalError("Excess data in RLE byte array string");
  404.  
  405.     return array;
  406.     }
  407.  
  408.     /**
  409.      * Format a String for representation in a source file.  This includes
  410.      * breaking it into lines escaping characters using octal notation
  411.      * when necessary (control characters and double quotes).
  412.      */
  413.     static final String formatForSource(String s) {
  414.     StringBuffer buffer = new StringBuffer();
  415.     for (int i=0; i<s.length();) {
  416.         if (i > 0) buffer.append("+\n");
  417.         buffer.append("        \"");
  418.         int count = 11;
  419.         while (i<s.length() && count<80) {
  420.         char c = s.charAt(i++);
  421.         if (c < '\u0020' || c == '"') {
  422.             // Represent control characters and the double quote
  423.             // using octal notation; otherwise the string we form
  424.             // won't compile, since Unicode escape sequences are
  425.             // processed before tokenization.
  426.             buffer.append('\\');
  427.             buffer.append(HEX_DIGIT[(c & 0700) >> 6]); // HEX_DIGIT works for octal
  428.             buffer.append(HEX_DIGIT[(c & 0070) >> 3]);
  429.             buffer.append(HEX_DIGIT[(c & 0007)]);
  430.             count += 4;
  431.         }
  432.         else if (c <= '\u007E') {
  433.             buffer.append(c);
  434.             count += 1;
  435.         }
  436.         else {
  437.             buffer.append("\\u");
  438.             buffer.append(HEX_DIGIT[(c & 0xF000) >> 12]);
  439.             buffer.append(HEX_DIGIT[(c & 0x0F00) >> 8]);
  440.             buffer.append(HEX_DIGIT[(c & 0x00F0) >> 4]);
  441.             buffer.append(HEX_DIGIT[(c & 0x000F)]);
  442.             count += 6;
  443.         }
  444.         }
  445.         buffer.append('"');
  446.     }
  447.     return buffer.toString();
  448.     }
  449.  
  450.     static final char[] HEX_DIGIT = {'0','1','2','3','4','5','6','7',
  451.                      '8','9','A','B','C','D','E','F'};
  452. }
  453.  
  454.